﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Pear.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace Pear.Application.UserCenter
{
    /// <summary>
    /// 权限服务
    /// </summary>
    [ApiDescriptionSettings(ApiGroupConsts.USER_CENTER)]
    public class SecurityService : ISecurityService, IDynamicApiController, ITransient
    {
        /// <summary>
        /// 权限仓储
        /// </summary>
        private readonly IRepository<Security> _securityRepository;

        /// <summary>
        /// 角色仓储
        /// </summary>
        private readonly IRepository<Role> _roleRepository;

        /// <summary>
        /// 内存缓存
        /// </summary>
        private readonly IMemoryCache _memoryCache;

        /// <summary>
        /// 用户管理
        /// </summary>
        private readonly IUserManager _userManager;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="securityRepository"></param>
        /// <param name="roleRepository"></param>
        /// <param name="memoryCache"></param>
        /// <param name="userManager"></param>
        public SecurityService(IRepository<Security> securityRepository
            , IRepository<Role> roleRepository
            , IMemoryCache memoryCache
            , IUserManager userManager)
        {
            _securityRepository = securityRepository;
            _roleRepository = roleRepository;
            _memoryCache = memoryCache;
            _userManager = userManager;
        }

        /// <summary>
        /// 刷新用户权限菜单缓存
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [SecurityDefine(SecurityConsts.SECURITY_SERVICE_REFRESH)]
        public async Task Refresh([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的用户 Id"), ApiSeat(ApiSeats.ActionStart)] int userId)
        {
            // 查询用户是否存在
            _ = await _userManager.CheckUserAsync(userId, false);
            _memoryCache.Remove($"{userId}_securities");
        }

        /// <summary>
        /// 获取所有权限菜单列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine("admin.system.security:view"), HttpGet, ApiDescriptionSettings(Name = "list")]
        public async Task<PagedList<SecurityProfile>> GetListAsync([FromQuery, Required] GetSecurityListInput input)
        {
            var hasKeyword = !string.IsNullOrEmpty(input.Keyword?.Trim());

            var securities = await _securityRepository.Where(
                                                (hasKeyword, u => EF.Functions.Like(u.Name, $"%{input.Keyword.Trim()}%")),
                                                (hasKeyword, u => EF.Functions.Like(u.Authorize, $"%{input.Keyword.Trim()}%")),
                                                (hasKeyword, u => EF.Functions.Like(u.Remark, $"%{input.Keyword.Trim()}%"))
                                              )
                                             .OrderBy(u => u.Sequence)
                                             .ToPagedListAsync(input.PageIndex, input.PageSize);

            return securities.Adapt<PagedList<SecurityProfile>>();
        }

        /// <summary>
        /// 获取所有权限菜单列表（不分页）
        /// </summary>
        /// <returns></returns>
        [SecurityDefine("admin.system.security:view"), HttpGet, ApiDescriptionSettings(Name = "all")]
        public async Task<List<SecurityProfile>> GetAllAsync()
        {
            var securities = await _securityRepository.Where(u=>u.Id > 0).OrderBy(u => u.Sequence).ToListAsync();
            return securities.Adapt<List<SecurityProfile>>();
        }

        /// <summary>
        /// 为角色分配权限菜单
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="securityIds"></param>
        /// <returns></returns>
        [SecurityDefine("admin.system.role:give")]
        public async Task GiveAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的角色 Id")] int roleId, [Required, MinLength(1)] List<int> securityIds)
        {
            // 禁止为超级管理员分配角色权限
            if (roleId == 1) throw Oops.Oh(SystemErrorCodes.u1010);

            // 查询角色是否存在
            var role = await _roleRepository.FirstOrDefaultAsync(u => u.Id == roleId, false);
            _ = role ?? throw Oops.Oh(SystemErrorCodes.u1002);

            // 判断传入权限数据是否正确
            var count = await _securityRepository.CountAsync(u => securityIds.Contains(u.Id), false);
            if (securityIds.Contains(0) || count != securityIds.Count) throw Oops.Oh(SystemErrorCodes.u1009);

            // 删除已有的权限
            var roleSecurityRepository = _roleRepository.Change<RoleSecurity>();
            await roleSecurityRepository.DeleteAsync(roleSecurityRepository.Where(u => u.RoleId == roleId, false).ToList());

            var list = new List<RoleSecurity>();
            foreach (var securityId in securityIds)
            {
                list.Add(new RoleSecurity { RoleId = roleId, SecurityId = securityId });
            }

            await roleSecurityRepository.InsertAsync(list);
        }


        /// <summary>
        /// 获取权限菜单实体
        /// </summary>
        /// <param name="securityId">权限菜单编号</param>
        /// <returns></returns>
        [SecurityDefine("admin.system.security:view"), HttpGet]
        public async Task<SecurityProfile> ProfileAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的权限 Id")] int securityId)
        {
            // 查询角色是否存在
            var security = await _securityRepository.FirstOrDefaultAsync(u => u.Id == securityId, false);
            return security.Adapt<SecurityProfile>();
        }



        /// <summary>
        /// 修改权限菜单
        /// </summary>
        /// <param name="securityId"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine("admin.system.security:edit")]
        public async Task ModifyAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的权限 Id"), ApiSeat(ApiSeats.ActionStart)] int securityId, [Required] EditSecurityInput input)
        {
            // 查询菜单是否存在
            var isExist = await _securityRepository.AnyAsync(u => u.Id == securityId, false);
            if (!isExist) throw Oops.Oh(SystemErrorCodes.u1002);

            var modifySecurity = input.Adapt<Security>();

            // 配置主键和更新时间
            modifySecurity.Id = securityId;
            modifySecurity.UpdatedTime = DateTimeOffset.Now;

            await _securityRepository.UpdateExcludeAsync(modifySecurity, new[] { nameof(Role.IsDeleted), nameof(Role.CreatedTime) }, ignoreNullValues: true);
        }

        /// <summary>
        /// 改变权限菜单状态
        /// </summary>
        /// <param name="securityId"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine("admin.system.security:edit"), HttpPost]
        public async Task ChangeEnabledAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的权限 Id"), ApiSeat(ApiSeats.ActionStart)] int securityId, [Required] ChangeEnabledInput input)
        {
            // 查询菜单是否存在
            var isExist = await _securityRepository.AnyAsync(u => u.Id == securityId, false);
            if (!isExist) throw Oops.Oh(SystemErrorCodes.u1002);

            var security = input.Adapt<Security>();

            // 配置主键和更新时间
            security.Id = securityId;
            security.UpdatedTime = DateTimeOffset.Now;

            await _securityRepository.UpdateExcludeAsync(security, new[] { nameof(Security.IsDeleted), nameof(Security.CreatedTime) }, ignoreNullValues: true);
        }


        /// <summary>
        /// 新增权限菜单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [ApiDescriptionSettings(KeepVerb = true), SecurityDefine("admin.system.security:add")]
        public async Task<SecurityProfile> AddAsync([Required] EditSecurityInput input)
        {
            // 判断分类名是否存在
            var isExist = await _securityRepository.AnyAsync(u => u.Name.Trim().Equals(input.Name.Trim()));
            if (isExist) throw Oops.Oh(SystemErrorCodes.u1006);

            var addSecurity = input.Adapt<Security>();

            var entryEntity = await _securityRepository.InsertNowAsync(addSecurity);
            return entryEntity.Entity.Adapt<SecurityProfile>();
        }



        /// <summary>
        /// 删除权限菜单
        /// </summary>
        /// <param name="securityId"></param>
        /// <returns></returns>
        [SecurityDefine("admin.system.security:delete")]
        public async Task DeleteAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的权限 Id"), ApiSeat(ApiSeats.ActionStart)] int securityId)
        {
            // 查询菜单是否存在
            var deleteSecurity = await _securityRepository.FindAsync(securityId);
            _ = deleteSecurity ?? throw Oops.Oh(SystemErrorCodes.u1002);

            // 查询分类是否被其他数据引用
            var isRef = await _securityRepository.Include(u => u.Sublevels, false)
                                                 .Include(u => u.Roles)
                                                 .AnyAsync(u => u.Id == securityId && (u.Sublevels.Any() || u.Roles.Any()));

            if (isRef) throw Oops.Oh(SystemErrorCodes.u1007);

            // 软/假删除
            deleteSecurity.UpdatedTime = DateTimeOffset.Now;
            deleteSecurity.IsDeleted = true;
        }




    }
}